package grpcutil

import (
	"errors"
	"reflect"

	"gitee.com/xuyiping_admin/pkg/xerr"

	spb "google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// StatusError cause of grpc status error
func StatusError(err error) (*status.Status, bool) {
	statusErr, ok := status.FromError(xerr.Cause(err))
	if !ok {
		return nil, false
	}

	return statusErr, true
}

// FilterServerError 优化服务端错误上报逻辑
func FilterServerError(err error) bool {
	statusErr, ok := StatusError(err)
	if !ok {
		return true
	}

	details := statusErr.Details()
	for _, detail := range details {
		if _, ok := detail.(*spb.Status); ok && statusErr.Code() != codes.Canceled {
			return false
		}
	}

	ignoreStatus := []codes.Code{codes.InvalidArgument, codes.Unauthenticated, codes.NotFound, codes.FailedPrecondition, codes.AlreadyExists}
	if inArray, _ := In(statusErr.Code(), ignoreStatus); inArray {
		return false
	}
	return true
}

func In(obj interface{}, target interface{}) (bool, error) {
	targetValue := reflect.ValueOf(target)
	switch reflect.TypeOf(target).Kind() {
	case reflect.Slice, reflect.Array:
		for i := 0; i < targetValue.Len(); i++ {
			if targetValue.Index(i).Interface() == obj {
				return true, nil
			}
		}
	case reflect.Map:
		if targetValue.MapIndex(reflect.ValueOf(obj)).IsValid() {
			return true, nil
		}
	}

	return false, errors.New("not in array")
}
